package com.heiyanqiang.controller;

import com.heiyanqiang.domain.SysLog;
import com.heiyanqiang.service.LogAopService;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.After;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.core.context.SecurityContext;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.core.userdetails.User;
import org.springframework.stereotype.Component;
import org.springframework.web.bind.annotation.RequestMapping;

import javax.servlet.http.HttpServletRequest;
import java.lang.annotation.Annotation;
import java.lang.reflect.Method;
import java.util.Date;

@Component
@Aspect
public class LogAop {

    //注入request对象，帮助获取访问的ip
    @Autowired
    private HttpServletRequest request;

    //注入service对象
    @Autowired
    private LogAopService logAopService;

    private Date visitTime; //开始的时间
    private Class clazz;    //访问的类
    private Method method; //访问的方法

    //前置通知
    //主要获取开始时间，执行的类是哪一个，执行的是哪一个方法
    @Before("execution(* com.heiyanqiang.controller.*.*(..))")
    public void doBefore(JoinPoint jp) throws NoSuchMethodException {
        visitTime = new Date(); //获取当前时间，就是开始访问的时间

        clazz=jp.getTarget().getClass();    //获取具体要访问的类

        String methodName = jp.getSignature().getName();//获取访问的方法的名称
        Object[] args = jp.getArgs();   //获取访问的方法的参数
        //获取具体执行方法的method对象
        if(args==null||args.length==0){
            method=clazz.getMethod(methodName);    //获取无参数的方法
        }else {
            //定义一个class数组，存放方法的参数
            Class[] classArgs = new Class[args.length];
            for (int i = 0; i < args.length; i++) {
                //获取方法的参数
                classArgs[i] = args[i].getClass();
            }
            method = clazz.getMethod(methodName, classArgs);    //获取有参数的方法
        }

    }



    //后置通知
    @After("execution(* com.heiyanqiang.controller.*.*(..))")
    public void doAfter(JoinPoint jp){
        //获取访问时长
        long time = new Date().getTime() - visitTime.getTime();
        String url = "";
        //获取url
        if(clazz!=null&&method!=null&&clazz!=LogAop.class){
            //1、获取类上的@RequestMapping    需要强制转换
            //使用类名.getAnnotation,获取方法名上的url
            RequestMapping clazzAnnotation = (RequestMapping) clazz.getAnnotation(RequestMapping.class);
            if(clazzAnnotation != null){
                String[] classValue = clazzAnnotation.value();
                //2、获取方法上的@ResquestMapping
                //使用方法名.getAnnotation
                RequestMapping methodAnnotation = method.getAnnotation(RequestMapping.class);
                if(methodAnnotation!=null){
                    String[] methodValue = methodAnnotation.value();
                    url = classValue[0]+methodValue[0];
                }
            }

            //获取访问的ip地址
            //web.xml文件中配置监听器，帮助aop获取ip
            //web文件listener配置路径 org.springframework.web.context.request.RequestContextListener
            //配置完之后可以在本类中注入一个request对象

            //获取到ip地址
            String ip = request.getRemoteAddr();

            //获取当前操作的用户
            SecurityContext context = SecurityContextHolder.getContext();   //从上下文中获取当前登录的用户
            User user = (User) context.getAuthentication().getPrincipal();
            String username = user.getUsername();

            //也可以通过request从session中获取
            //User context1 = (User) request.getSession().getAttribute("SPRING_SECURITY_CONTEXT");
            //String username = context1.getUsername();

            SysLog sysLog = new SysLog();
            sysLog.setVisitTime(visitTime);
            sysLog.setExecutionTime(time);
            sysLog.setIp(ip);
            sysLog.setMethod("[类名]"+clazz.getName()+"[方法名]"+method.getName());
            sysLog.setUrl(url);
            sysLog.setUsername(username);

            //调用service完成操作
            logAopService.save(sysLog);
        }
    }


}
